const _ = require('lodash')
const Eta = require('eta')
const { getFileContent, getFileJson } = require('./files')
const { join } = require('path')

const getTemplates = (rootPath, config) => {
	const templatesPath = join(__dirname, 'templates')
	const coreSrcPath = join(rootPath, config.project.corePath, config.project.coreSrcPath)
	const vueSrcPath = join(rootPath, config.project.vuePath, config.project.vueSrcPath)

	console.log('✨ try to', 'read'.yellow, 'templates'.green, 'from directory', `"${templatesPath}"`.underline)

	const coreTemplateConfigs = {
		Consts: {
			path: join(templatesPath, './aspnet-core/Domain.Shared/Consts.eta'),
			output: join(coreSrcPath, config.project.domainSharedPath, config.entity.namespace),
			outputFileName: `${config.entity.entityName}Consts.cs`,
			type: 1, // type === 1 创建, // type === 2 修改
			env: 'core',
		},
		Entity: {
			path: join(templatesPath, './aspnet-core/Domain/Entity.eta'),
			output: join(coreSrcPath, config.project.domainPath, config.entity.namespace),
			outputFileName: `${config.entity.entityName}.cs`,
			type: 1,
			env: 'core',
		},
		DbContext: {
			path: join(coreSrcPath, config.project.entityFrameworkCorePath, config.project.dbContextPath, `${config.project.dbContextName}.cs`),
			output: join(coreSrcPath, config.project.entityFrameworkCorePath, config.project.dbContextPath),
			outputFileName: `${config.project.dbContextName}.cs`,
			type: 2,
			rules: [
				{
					content: `using ${config.project.companyName}.${config.project.projectName}.${config.entity.namespace};`,
				},
				{
					// 增加Dbset, eg: public DbSet<AppUser> Users { get; set; }
					anchor: `${config.project.dbContextAnchor}`,
					content: `\t\tpublic DbSet<${config.entity.entityName}> ${config.entity.entityNamePlural} { get; set; }`,
					pos: 1, // 1 代表在匹配到的下边加代码, 2 代表在匹配到的上边加代码, 3 直接替换
				},
			],
			env: 'core',
		},
		EntityDbContextModelCreatingExtensions: {
			path: join(templatesPath, './aspnet-core/EntityFrameworkCore/EntityDbContextModelCreatingExtensions.eta'),
			output: join(coreSrcPath, config.project.entityFrameworkCorePath, 'Extensions'),
			outputFileName: `${config.entity.entityName}DbContextModelCreatingExtensions.cs`,
			type: 1,
			env: 'core',
		},
		DbContextModelCreatingExtensions: {
			path: join(coreSrcPath, config.project.entityFrameworkCorePath, config.project.dbContextPath, `${config.project.dbContextModelCreatingExtensionsName}.cs`),
			output: join(coreSrcPath, config.project.entityFrameworkCorePath, config.project.dbContextPath),
			outputFileName: `${config.project.dbContextModelCreatingExtensionsName}.cs`,
			type: 2,
			rules: [
				{
					content: `using ${config.project.companyName}.${config.project.projectName}.EntityFrameworkCore.Extensions;`,
				},
				{
					// 配置
					anchor: `${config.project.dbContextModelCreatingExtensionsAnchor}`,
					content: `\t\t\tbuilder.${config.entity.entityName}Configure();`,
					pos: 1, // 1 代表在匹配到的下边加代码, 2 代表在匹配到的上边加代码, 3 直接替换
				},
			],
			env: 'core',
		},
		Dto: {
			path: join(templatesPath, './aspnet-core/Application.Contracts/Dto.eta'),
			output: join(coreSrcPath, config.project.applicationContractsPath, config.entity.namespace),
			outputFileName: `${config.entity.entityName}Dto.cs`,
			type: 1,
			env: 'core',
		},
		CreateUpdateDto: {
			path: join(templatesPath, './aspnet-core/Application.Contracts/CreateUpdateDto.eta'),
			output: join(coreSrcPath, config.project.applicationContractsPath, config.entity.namespace),
			outputFileName: `CreateUpdate${config.entity.entityName}Dto.cs`,
			type: 1,
			env: 'core',
		},
		EntityAutoMapperProfile: {
			path: join(templatesPath, './aspnet-core/Application/EntityAutoMapperProfile.eta'),
			output: join(coreSrcPath, config.project.applicationPath, config.entity.namespace, 'AutoMapper'),
			outputFileName: `${config.entity.entityName}AutoMapperProfile.cs`,
			type: 1,
			env: 'core',
		},
		EnLocalization: {
			path: join(coreSrcPath, config.project.domainSharedPath, config.project.localizationPath, 'en.json'),
			output: join(coreSrcPath, config.project.domainSharedPath, config.project.localizationPath),
			outputFileName: 'en.json',
			type: 3,
			keysPath: 'texts', // 要把 content 加入到某个 key 下, 多层可以用 '.' 隔开, eg: 'a.b.c'
			content: [
				{
					key: `Permission:${config.entity.entityNamePlural}`,
					value: `${config.entity.entityName} Management`,
				},
				{
					key: `Permission:${config.entity.entityNamePlural}.Create`,
					value: `Creating new ${config.entity.entityName}`,
				},
				{
					key: `Permission:${config.entity.entityNamePlural}.Edit`,
					value: `Editing the ${config.entity.entityName}`,
				},
				{
					key: `Permission:${config.entity.entityNamePlural}.Delete`,
					value: `Deleting the ${config.entity.entityName}`,
				},
			],
			env: 'core',
		},
		CnLocalization: {
			path: join(coreSrcPath, config.project.domainSharedPath, config.project.localizationPath, 'zh-Hans.json'),
			output: join(coreSrcPath, config.project.domainSharedPath, config.project.localizationPath),
			outputFileName: 'zh-Hans.json',
			type: 3,
			keysPath: 'texts',
			content: [
				{
					key: `Permission:${config.entity.entityNamePlural}`,
					value: `${config.entity.entityCnName}管理`,
				},
				{
					key: `Permission:${config.entity.entityNamePlural}.Create`,
					value: `创建新的${config.entity.entityCnName}`,
				},
				{
					key: `Permission:${config.entity.entityNamePlural}.Edit`,
					value: `编辑${config.entity.entityCnName}`,
				},
				{
					key: `Permission:${config.entity.entityNamePlural}.Delete`,
					value: `删除${config.entity.entityCnName}`,
				},
			],
			env: 'core',
		},
		Permissions: {
			path: join(templatesPath, './aspnet-core/Application.Contracts/Permissions.eta'),
			output: join(coreSrcPath, config.project.applicationContractsPath, config.entity.namespace, 'Permissions'),
			outputFileName: `${config.entity.entityName}Permissions.cs`,
			type: 1,
			env: 'core',
		},
		PermissionDefinitionProvider: {
			path: join(templatesPath, './aspnet-core/Application.Contracts/PermissionDefinitionProvider.eta'),
			output: join(coreSrcPath, config.project.applicationContractsPath, config.entity.namespace, 'Permissions'),
			outputFileName: `${config.entity.entityName}PermissionDefinitionProvider.cs`,
			type: 1,
			env: 'core',
		},
		IAppService: {
			path: join(templatesPath, './aspnet-core/Application.Contracts/IAppService.eta'),
			output: join(coreSrcPath, config.project.applicationContractsPath, config.entity.namespace),
			outputFileName: `I${config.entity.entityName}AppService.cs`,
			type: 1,
			env: 'core',
		},
		IAppService: {
			path: join(templatesPath, './aspnet-core/Application.Contracts/IAppService.eta'),
			output: join(coreSrcPath, config.project.applicationContractsPath, config.entity.namespace),
			outputFileName: `I${config.entity.entityName}AppService.cs`,
			type: 1,
			env: 'core',
		},
		AppService: {
			path: join(templatesPath, './aspnet-core/Application/AppService.eta'),
			output: join(coreSrcPath, config.project.applicationPath, config.entity.namespace),
			outputFileName: `${config.entity.entityName}AppService.cs`,
			type: 1,
			env: 'core',
		},
	}

	const vueTemplateConfigs = {
		api: {
			path: join(templatesPath, './vue/api/api.eta'),
			output: join(vueSrcPath, config.project.vueApiPath, config.entity._lowerNamespace),
			outputFileName: `${config.entity._lowerEntityName}.js`,
			type: 1, // type === 1 创建, // type === 2 修改
			env: 'vue',
		},
		router: {
			path: join(templatesPath, './vue/router/router.eta'),
			output: join(vueSrcPath, config.project.vueRouterPath, 'coder'),
			outputFileName: `${config.entity._lowerEntityName}.js`,
			type: 1, // type === 1 创建, // type === 2 修改
			env: 'vue',
		},
		viewIndex: {
			path: join(templatesPath, './vue/view/index.eta'),
			output: join(vueSrcPath, config.project.vueViewsPath, config.entity._lowerNamespace),
			outputFileName: `index.vue`,
			type: 1, // type === 1 创建, // type === 2 修改
			env: 'vue',
		},
		viewCreateUpdateDialog: {
			path: join(templatesPath, './vue/view/createUpdateDialog.eta'),
			output: join(vueSrcPath, config.project.vueViewsPath, config.entity._lowerNamespace),
			outputFileName: `create-update-dialog.vue`,
			type: 1, // type === 1 创建, // type === 2 修改
			env: 'vue',
		},
	}

	const templateConfigs = Object.assign(coreTemplateConfigs, vueTemplateConfigs)

	const templatesMap = _.forIn(templateConfigs, (template, key) => {
		try {
			let fileContent = template.type === 3 ? getFileJson(template.path) : getFileContent(template.path)
			if (template.type !== 3) fileContent = _.trimStart(fileContent)

			if (!fileContent) {
				throw `❗❗❗ ${_.lowerCase(key)} template not found in ${template.path}\n`
			}

			// 替换需要解析自定义的 content
			if (template.type === 2) {
				_.forEach(template.rules, (rule) => {
					// 如果已经有了就返回
					if (fileContent.indexOf(_.trim(rule.content)) > -1) return

					if (!rule.anchor) {
						// 没有 描点的默认放在最上放
						fileContent = `${rule.content}\r\n${fileContent}`

						return
					}

					if (rule.pos === 1) {
						fileContent = fileContent.replace(rule.anchor, `${rule.anchor}\r\n\r\n${rule.content}`)
					} else if (rule.pos === 2) {
						fileContent = fileContent.replace(rule.anchor, `${rule.content}\r\n\r\n${rule.anchor}`)
					} else {
						fileContent = fileContent.replace(rule.anchor, rule.content)
					}
				})
			}

			// json 数据转换
			if (template.type === 3) {
				const obj = _.get(fileContent, template.keysPath)

				if (template.content) {
					_.forEach(template.content, (item) => {
						if (!obj[item.key]) {
							obj[item.key] = item.value
						}
					})
				}
			}

			template.content = fileContent
		} catch (error) {
			console.error(error)
		}
	})

	return templatesMap
}

const renderTemplate = (template, configuration, options) => {
	if (template.type === 1) {
		configuration._ = _
		template.render = Eta.render(template.content, configuration, { async: false, ...(options || {}) })
		return
	}

	template.render = template.content
}

module.exports = {
	getTemplates,
	renderTemplate,
}
